package com.ajavaer.framework.core.orm;

import com.ajavaer.framework.common.message.PageMessage;
import com.ajavaer.framework.common.spring.SpringContext;
import com.ajavaer.framework.common.tools.JsonTools;
import com.ajavaer.framework.common.tools.StringTools;
import com.ajavaer.framework.core.tools.FreemarkerTools;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLQueryExpr;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import freemarker.template.Template;

import javax.persistence.EntityManager;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TemplateBuilder {
    private Map<String, Object> params;
    private RunSQL runSQL;
    private Template template;
    private String sql;

    public TemplateBuilder(Template template) {
        this.template = template;
        this.runSQL = SpringContext.getBean(RunSQL.class);
        this.params = new HashMap<>();
    }

    public TemplateBuilder param(String name, Object value) {
        this.params.put(name, value);
        return this;
    }

    public List<Map<String, Object>> query() {
        return runSQL.executeMap(getSql(), this.params);
    }

    public PageMessage query(int page, int limit) {
        SQLExpr exp = SQLUtils.toMySqlExpr(getSql());
        MySqlSelectQueryBlock select = (MySqlSelectQueryBlock) (((SQLQueryExpr) exp).getSubQuery().getQuery());
        MySqlSelectQueryBlock rmOrderBy = select.clone();
        rmOrderBy.setOrderBy(null);
        String countSql = StringTools.format("select count(0) from ({0}) forCount", rmOrderBy.toString());
        long totalCount = runSQL.executeSQLForCount(countSql, this.params);
        select.limit(limit,((page - 1) * limit));
        List<Map<String, Object>> executeMap = runSQL.executeMap(select.toString(), this.params);
        return PageMessage.of(page, limit, totalCount, executeMap);
    }

    public <T> PageMessage<List<T>> query(int page, int limit, Class<T> clazz) {
        PageMessage query = query(page, limit);
        Object data = query.getData();
        query.setData(JsonTools.jsonToList(JsonTools.beanToJson(data), clazz));
        return query;
    }

    public <T> List<T> query(Class<T> clazz) {
        return runSQL.executeObject(getSql(), clazz, this.params);
    }

    public int update() {
        return runSQL.executeUpdate(getSql(), params);
    }

    public int updateWithoutTx(EntityManager entityManager) {
        return runSQL.executeUpdateWithoutTx(entityManager, getSql(), params);
    }

    private String templateSql() {
        return FreemarkerTools.processTemplate(template, params).trim();
    }

    public String getSql() {
        return sql == null ? sql = templateSql() : sql;
    }
}
